package com.desaysv.svview.refresh

import android.animation.Animator
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.TypedArray
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.util.AttributeSet
import android.util.Log
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.webkit.WebView
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.LinearLayout.VERTICAL
import android.widget.ListView
import android.widget.ScrollView
import androidx.recyclerview.widget.RecyclerView
import com.desaysv.svview.R
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.math.abs

class RefreshLayout @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attributeSet, defStyleAttr) {

    companion object {
        private const val TAG = "RefreshLayout"
    }

    private val headerLayout = FrameLayout(context)
    private val rootLayout = FrameLayout(context)
    private val footLayout = FrameLayout(context)
    private val container = LinearLayout(context)

    private var width = 0
    private var height = 0

    private var orientation = VERTICAL
    private var headerBg = -1
    private var footBg = -1
    private var headerMax = -1
    private var footMax = -1
    private var scrollWithIng = false

    interface OnRefreshListener {
        fun onRefreshStarting()
        fun onRefreshComplete()
        fun onLoadingStarting()
        fun onLoadingComplete()
    }

    private var listener: OnRefreshListener? = null
    fun setOnRefreshListener(listener: OnRefreshListener) {
        this.listener = listener
    }

    init {
        attributeSet?.let {
            val typedArray: TypedArray =
                context.obtainStyledAttributes(it, R.styleable.RefreshLayout)
            orientation = typedArray.getInt(R.styleable.RefreshLayout_orientation, VERTICAL)
            headerBg = typedArray.getResourceId(R.styleable.RefreshLayout_header_bg, -1)
            footBg = typedArray.getInt(R.styleable.RefreshLayout_foot_bg, -1)
            headerMax = typedArray.getDimensionPixelSize(
                R.styleable.RefreshLayout_header_max,
                500
            )
            footMax = typedArray.getDimensionPixelSize(
                R.styleable.RefreshLayout_foot_max,
                500
            )
            scrollWithIng=typedArray.getBoolean(R.styleable.RefreshLayout_scroll_with_ing, false)
            typedArray.recycle()
        }
        this.clipChildren = false
        container.clipChildren = false
        container.fitsSystemWindows = true
        this.fitsSystemWindows = true
    }


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        //测量控件的真实高度
        val width = MeasureSpec.getSize(widthMeasureSpec)
        val height = MeasureSpec.getSize(heightMeasureSpec)
        if (width == 0 || height == 0) {
            return
        }
        if (width == this.width && height == this.height) {
            return
        }

        this.width = width
        this.height = height
        Log.i(TAG, "onMeasure: width=$width , height=$height")

        resize()
    }

    private var refreshHeader: BaseRefreshHeader? = null
    private var refreshFoot: BaseRefreshFoot? = null

    @SuppressLint("ClickableViewAccessibility")
    private fun reLayout() {
        val childrenCount = this.childCount
        val children = ArrayList<View>()
        for (i in 0 until childrenCount) {
            val child = this.getChildAt(i)
            children.add(child)
        }
        this.removeAllViews()

        val lp = LayoutParams(
            LayoutParams.MATCH_PARENT,
            LayoutParams.MATCH_PARENT
        )
        this.addView(container, lp)
        container.orientation = orientation

        rootLayout.removeAllViews()
        for (child in children) {
            if (child is BaseRefreshHeader) {
                if (refreshHeader != null) {
                    continue
                }
                refreshHeader = child
                headerLayout.addView(child)
                if (orientation == VERTICAL) {
                    (child.layoutParams as FrameLayout.LayoutParams).gravity = Gravity.BOTTOM
                } else {
                    (child.layoutParams as FrameLayout.LayoutParams).gravity = Gravity.END
                }
            } else if (child is BaseRefreshFoot) {
                if (refreshFoot != null) {
                    continue
                }
                refreshFoot = child
                footLayout.addView(child)
                if (orientation == VERTICAL) {
                    (child.layoutParams as FrameLayout.LayoutParams).gravity = Gravity.TOP
                } else {
                    (child.layoutParams as FrameLayout.LayoutParams).gravity = Gravity.START
                }
            } else {
                rootLayout.addView(child)
            }
        }
        if (refreshHeader == null) {
            refreshHeader = DefaultRefreshHeader(context)
            if (orientation == VERTICAL) {
                val lp = LayoutParams(
                    LayoutParams.MATCH_PARENT,
                    headerMax/2
                )
                headerLayout.addView(refreshHeader!!, lp)
            } else {
                val lp = LayoutParams(
                    headerMax/2,
                    LayoutParams.MATCH_PARENT
                )
                headerLayout.addView(refreshHeader!!, lp)
            }
        }
        if (refreshFoot == null) {
            refreshFoot = DefaultRefreshFoot(context)
            if (orientation == VERTICAL) {
                val lp = LayoutParams(
                    LayoutParams.MATCH_PARENT,
                    footMax/2
                )
                footLayout.addView(refreshHeader!!, lp)
            } else {
                val lp = LayoutParams(
                    footMax/2,
                    LayoutParams.MATCH_PARENT
                )
                footLayout.addView(refreshHeader!!, lp)
            }
        }

        container.addView(headerLayout)
        container.addView(rootLayout)
        container.addView(footLayout)
    }

    private var initialX = 0f
    private var initialY = 0f
    private var initialTouchX = 0f
    private var initialTouchY = 0f
    private var lastY = 0f
    private var lastX = 0f
    private var isRefresh = false
    private var isLoad = false

    // 添加变量用于跟踪滑动方向和是否可以下拉刷新
    private var isTop = false
    private var isBottom = false
    private var needStartRefreshOrLoad = false
    private var hasMove=false
    override fun dispatchTouchEvent(event: MotionEvent): Boolean {
        if((isRefreshing.get()||isLoading.get())){
            if(scrollWithIng) {
                rootLayout.dispatchTouchEvent(event)
            }
            return true
        }

        // 检查是否可以下拉或上拉
        isTop = isTopOrBottom(true) // 检查是否在顶部
        isBottom = isTopOrBottom(false) // 检查是否在底部

        if (event.action == MotionEvent.ACTION_DOWN) {
            initialX = this.x
            initialY = this.y

            initialTouchX = event.rawX
            initialTouchY = event.rawY

            lastX = container.x
            lastY = container.y
            rootLayout.dispatchTouchEvent(event)
        }
        if (event.action == MotionEvent.ACTION_MOVE) {
            val x = (initialX + event.rawX - initialTouchX) * 0.5f
            val y = (initialY + event.rawY - initialTouchY)* 0.5f
            Log.i(TAG, "dispatchTouchEvent: x=$x ,  y=$y")
            var moveY = lastY + y
            var moveX = lastX + x
            isRefresh = false
            isLoad = false
            needStartRefreshOrLoad = false
            hasMove=false
            if (orientation == VERTICAL) {
                if (y > 0 && isTop) {
                    hasMove=true
                    isRefresh = true
                    isLoad = false
                    Log.e(TAG, "dispatchTouchEvent: moveY=$moveY" )
                    Log.e(TAG, "dispatchTouchEvent: headerLayout.measuredHeight - refreshHeader!!.measuredHeight=${headerLayout.measuredHeight - refreshHeader!!.measuredHeight}" )
                    if (moveY >= (headerLayout.measuredHeight - refreshHeader!!.measuredHeight)*-1) {
                        needStartRefreshOrLoad = true
                    }
                }
                if (y < 0 && isBottom) {
                    hasMove=true
                    isRefresh = false
                    isLoad = true
                    if (abs(moveY) >= footLayout.measuredHeight + refreshFoot!!.measuredHeight) {
                        needStartRefreshOrLoad = true
                    }
                }
                //下拉的极限值
                if (moveY >= 0f) {
                    moveY = 0f
                }
                //上拉的极限值
                if (moveY <= (footLayout.measuredHeight + headerLayout.measuredHeight) * -1f) {
                    moveY = (footLayout.measuredHeight + headerLayout.measuredHeight) * -1f
                }
                Log.i(TAG, "dispatchTouchEvent: isRefresh=$isRefresh")
                Log.i(TAG, "dispatchTouchEvent: isLoad=$isLoad")
                post {
                    if (!isRefreshing.get() && !isLoading.get()
                        && ((isRefresh && isTop) || (isLoad && isBottom))
                    ) {
                        container.y = moveY
                        if (isRefresh) {
                            refreshHeader?.let {
                                it.headerTouch(y, orientation)
                            }
                        }
                        if (isLoad) {
                            refreshFoot?.let {
                                it.headerTouch(abs(y), orientation)
                            }
                        }
                    } else {
                        rootLayout.dispatchTouchEvent(event)
                    }
                }
            } else {
                if (x > 0 && isTop) {
                    hasMove=true
                    isRefresh = true
                    isLoad = false
                    if (abs(moveX) <= headerLayout.measuredWidth - refreshHeader!!.measuredWidth) {
                        needStartRefreshOrLoad = true
                    }
                }
                if (x < 0 && isBottom) {
                    hasMove=true
                    isRefresh = false
                    isLoad = true
                    if (abs(moveX) >= footLayout.measuredWidth + refreshFoot!!.measuredWidth) {
                        needStartRefreshOrLoad = true
                    }
                }
                //下拉的极限值
                if (moveX >= 0f) {
                    moveX = 0f
                }
                //上拉的极限值
                if (moveX <= (footLayout.measuredWidth + headerLayout.measuredWidth) * -1f) {
                    moveX = (footLayout.measuredWidth + headerLayout.measuredWidth) * -1f
                }
                post {
                    if (!isRefreshing.get() && !isLoading.get()
                        && ((isRefresh && isTop) || (isLoad && isBottom))
                    ) {
                        container.x = moveX
                        if (isRefresh) {
                            refreshHeader?.let {
                                it.headerTouch(x, orientation)
                            }
                        }
                        if (isLoad) {
                            refreshFoot?.let {
                                it.headerTouch(abs(x), orientation)
                            }
                        }
                    } else {
                        rootLayout.dispatchTouchEvent(event)
                    }
                }
            }
        }
        if (event.action == MotionEvent.ACTION_UP) {
            if (isRefresh && !isRefreshing.get() && needStartRefreshOrLoad) {
                startRefresh()
            } else if (isLoad && !isLoading.get() && needStartRefreshOrLoad) {
                startLoading()
            } else if(hasMove){
                if (orientation == VERTICAL) {
                    container.animate()
                        .y(headerLayout.measuredHeight * -1f)
                        .setListener(null)
                        .setDuration(70).start()
                } else {
                    container.animate()
                        .x(headerLayout.measuredWidth * -1f)
                        .setListener(null)
                        .setDuration(70).start()
                }
            }
            if ((isRefresh && !isTop) || (isLoad && !isBottom)) {
                rootLayout.dispatchTouchEvent(event)
            }
            isRefresh = false
            isLoad = false
        }
        return true
    }

    fun stopRefresh() {
        post {
            isRefreshing.set(false)
            refreshHeader?.stopRefresh(object : BaseRefreshHeader.StopRefreshListener {
                override fun stopComplete() {
                    Log.i(TAG, "stopComplete: ")
                    if (orientation == VERTICAL) {
                        container.animate()
                            .y(headerLayout.layoutParams.height * -1f)
                            .setListener(null)
                            .setDuration(70).start()
                    } else {
                        container.animate()
                            .x(headerLayout.layoutParams.width * -1f)
                            .setListener(null)
                            .setDuration(70).start()
                    }
                    listener?.onRefreshComplete()
                }
            })
        }
    }

    fun startRefresh() {
        post {
            isRefreshing.set(true)
            refreshHeader?.let {
                if (orientation == VERTICAL) {
                    container.animate()
                        .y((headerLayout.measuredHeight - it.measuredHeight) * -1f)
                        .setDuration(70)
                        .setListener(object : Animator.AnimatorListener {
                            override fun onAnimationStart(animation: Animator) {

                            }

                            override fun onAnimationEnd(animation: Animator) {
                                it.startRefresh()
                                listener?.onRefreshStarting()
                            }

                            override fun onAnimationCancel(animation: Animator) {

                            }

                            override fun onAnimationRepeat(animation: Animator) {

                            }

                        })
                        .start()
                } else {
                    container.animate()
                        .x((headerLayout.measuredWidth - it.measuredWidth) * -1f)
                        .setDuration(70)
                        .setListener(object : Animator.AnimatorListener {
                            override fun onAnimationStart(animation: Animator) {

                            }

                            override fun onAnimationEnd(animation: Animator) {
                                it.startRefresh()
                                listener?.onRefreshStarting()
                            }

                            override fun onAnimationCancel(animation: Animator) {

                            }

                            override fun onAnimationRepeat(animation: Animator) {

                            }

                        })
                        .start()
                }
            }
        }
    }

    fun stopLoading() {
        post {
            isLoading.set(false)
            refreshFoot?.stopLoading(object : BaseRefreshFoot.StopLoadingListener {
                override fun stopComplete() {
                    Log.i(TAG, "stopComplete: ")
                    if (orientation == VERTICAL) {
                        container.animate()
                            .y(headerLayout.layoutParams.height * -1f)
                            .setListener(null)
                            .setDuration(70).start()
                    } else {
                        container.animate()
                            .x(headerLayout.layoutParams.width * -1f)
                            .setListener(null)
                            .setDuration(70).start()
                    }
                    listener?.onLoadingComplete()
                }
            })
        }
    }

    fun startLoading() {
        post {
            isLoading.set(true)
            refreshFoot?.let {
                if (orientation == VERTICAL) {
                    container.animate()
                        .y((headerLayout.measuredHeight + it.measuredHeight) * -1f)
                        .setDuration(70)
                        .setListener(object : Animator.AnimatorListener {
                            override fun onAnimationStart(animation: Animator) {

                            }

                            override fun onAnimationEnd(animation: Animator) {
                                it.startLoading()
                                listener?.onLoadingStarting()
                            }

                            override fun onAnimationCancel(animation: Animator) {

                            }

                            override fun onAnimationRepeat(animation: Animator) {

                            }

                        })
                        .start()
                } else {
                    container.animate()
                        .x((headerLayout.measuredWidth + it.measuredWidth) * -1f)
                        .setDuration(70)
                        .setListener(object : Animator.AnimatorListener {
                            override fun onAnimationStart(animation: Animator) {

                            }

                            override fun onAnimationEnd(animation: Animator) {
                                it.startLoading()
                                listener?.onLoadingStarting()
                            }

                            override fun onAnimationCancel(animation: Animator) {

                            }

                            override fun onAnimationRepeat(animation: Animator) {

                            }

                        })
                        .start()
                }
            }
        }
    }

    private fun resize() {
        if (headerBg == -1) {
            headerLayout.background = ColorDrawable(Color.parseColor("#dddddd"))
        } else {
            headerLayout.setBackgroundResource(headerBg)
        }
        if (footBg == -1) {
            footLayout.background = ColorDrawable(Color.parseColor("#dddddd"))
        } else {
            footLayout.setBackgroundResource(footBg)
        }
        val rootLp = LinearLayout.LayoutParams(width, height)
        rootLp.weight = 0F
        rootLayout.layoutParams = rootLp
        if (orientation == VERTICAL) {
            val headerLp = LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, headerMax)
            headerLp.weight = 0F
            headerLp.gravity = Gravity.BOTTOM
            headerLayout.layoutParams = headerLp
            val footLp = LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, footMax)
            footLp.weight = 0F
            footLp.gravity = Gravity.TOP
            footLayout.layoutParams = footLp
            container.y = headerLp.height * -1f
        } else {
            val headerLp = LinearLayout.LayoutParams(headerMax, LayoutParams.MATCH_PARENT)
            headerLp.weight = 0F
            headerLp.gravity = Gravity.START
            headerLayout.layoutParams = headerLp
            val footLp = LinearLayout.LayoutParams(footMax, LayoutParams.MATCH_PARENT)
            footLp.weight = 0F
            footLp.gravity = Gravity.END
            footLayout.layoutParams = footLp
            container.x = headerLp.width * -1f
        }
        Log.i(TAG, "resize: container.x=${container.x}")
        Log.i(TAG, "resize: container.y=${container.y}")
    }

    private val isRefreshing = AtomicBoolean(false)
    private val isLoading = AtomicBoolean(false)

    @SuppressLint("ClickableViewAccessibility")
    override fun onFinishInflate() {
        super.onFinishInflate()
        Log.i(TAG, "onFinishInflate: ")
        reLayout()
    }

    private fun isTopOrBottom(topOrBottom: Boolean): Boolean {
        var scollView: View? = null
        for (i in 0 until rootLayout.childCount) {
            val view = rootLayout.getChildAt(i)
            if ((view is ScrollView)
                || (view is WebView)
                || (view is ListView)
                || (view is RecyclerView)
            ) {
                scollView = view
                break
            }
        }
        scollView?.let {
            var res = true
            if (orientation == VERTICAL) {
                val isTop = it.canScrollVertically(-1)
                val isBottom = it.canScrollVertically(1)
                Log.i(
                    TAG,
                    "isTopOrBottom: canScrollVertically(-1)=$isTop ,canScrollVertically(1)=$isBottom"
                )
                res = if (topOrBottom) {
                    !isTop
                } else {
                    !isBottom
                }
            } else {
                val isTop = it.canScrollHorizontally(-1)
                val isBottom = it.canScrollHorizontally(1)
                Log.i(TAG, "isTopOrBottom: isTop=$isTop ,isBottom=$isBottom")
                res = if (topOrBottom) {
                    !isTop
                } else {
                    !isBottom
                }
            }
            Log.i(TAG, "isTopOrBottom: res=$res")
            return res
        }
        return true
    }
}